package cn.anecansaitin.industrialization_expansion.common.item.crafting;

import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.network.PacketBuffer;
import net.minecraft.tags.ITag;
import net.minecraft.tags.TagCollectionManager;
import net.minecraft.util.JSONUtils;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.common.crafting.IIngredientSerializer;
import net.minecraftforge.registries.ForgeRegistries;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import javax.annotation.Nonnull;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

public class LazyIngredientSerializer implements IIngredientSerializer<LazyIngredient> {
    private static final Logger LOGGER = LogManager.getLogger();
    public static final LazyIngredientSerializer INSISTENCE = new LazyIngredientSerializer();

    private LazyIngredientSerializer() {
    }

    @Override
    public @Nonnull LazyIngredient parse(PacketBuffer buffer) {
        if (buffer.readBoolean())
            return LazyIngredient.EMPTY;

        int tagSize = buffer.readInt();
        List<ITag.INamedTag<Item>> tags = null;

        if (tagSize > 0) {
            tags = new ArrayList<>(tagSize);

            for (int i = 0; i < tagSize; i++) {
                tags.set(i, (ITag.INamedTag<Item>) TagCollectionManager.getInstance().getItems().getTagOrEmpty(buffer.readResourceLocation()));
            }
        }

        int itemSize = buffer.readInt();
        ItemStack[] items = null;

        if (itemSize > 0) {
            items = new ItemStack[itemSize];

            for (int i = 0; i < itemSize; i++) {
                Item item = ForgeRegistries.ITEMS.getValue(buffer.readResourceLocation());

                if (item != null)
                    items[i] = item.getDefaultInstance();
            }
        }
        return LazyIngredient.of(tags, items);
    }

    @Override
    public @Nonnull LazyIngredient parse(@Nonnull JsonObject json) {
        ArrayList<ITag.INamedTag<Item>> tags = new ArrayList<>();
        ItemStack[] stacks = null;

        if (JSONUtils.isArrayNode(json, "tag")) {
            for (JsonElement element : JSONUtils.getAsJsonArray(json, "tag")) {
                ITag<Item> tag = TagCollectionManager.getInstance().getItems().getTag(new ResourceLocation(element.getAsString()));

                if (tag == null) {
                    LOGGER.error("Try to parse json to LazyIngredient, but defined illegal tag id: {}", element);
                    return LazyIngredient.EMPTY;
                }
                tags.add((ITag.INamedTag<Item>) tag);
            }
        }

        if (JSONUtils.isArrayNode(json, "item")) {
            JsonArray items = JSONUtils.getAsJsonArray(json, "item");
            stacks = new ItemStack[items.size()];
            int index = 0;

            for (JsonElement item : items) {
                Item value = ForgeRegistries.ITEMS.getValue(new ResourceLocation(item.getAsString()));

                if (value == null) {
                    LOGGER.error("Try to parse json to LazyIngredient, but defined illegal item id: {}", item);
                    return LazyIngredient.EMPTY;
                } else
                    stacks[index] = value.getDefaultInstance();
            }
        }

        return LazyIngredient.of(tags, stacks);
    }

    @Override
    public void write(@Nonnull PacketBuffer buffer, @Nonnull LazyIngredient ingredient) {
        if (ingredient == LazyIngredient.EMPTY) {
            buffer.writeBoolean(false);
            return;
        }

        List<ITag.INamedTag<Item>> tags = ingredient.getTags();

        if (tags != null) {
            buffer.writeInt(tags.size());
            tags.forEach(tag -> buffer.writeResourceLocation(tag.getName()));
        } else
            buffer.writeInt(0);

        ItemStack[] items = ingredient.getMarkingItems();

        if (items != null) {
            buffer.writeInt(items.length);
            Arrays.stream(items).forEach(item -> buffer.writeResourceLocation(Objects.requireNonNull(item.getItem().getRegistryName())));
        } else
            buffer.writeInt(0);
    }
}
